package com.xiran.srpingboottemplateself.exception;

import com.xiran.srpingboottemplateself.common.Response;
import com.xiran.srpingboottemplateself.common.ResponseCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    // ========== 新增：Spring Security 异常处理 ==========

    /**
     * 处理认证失败异常（401）
     * 例如：用户名密码错误、Token无效、Token过期等
     */
    @ExceptionHandler({
            BadCredentialsException.class,
            CredentialsExpiredException.class,
            UsernameNotFoundException.class,
            InsufficientAuthenticationException.class // 通常表示请求未携带认证信息
    })
    public Response<Void> handleAuthenticationException(AuthenticationException e, HttpServletRequest req) {
        log.warn("[AuthenticationException] {} -> {}", req.getRequestURI(), e.getMessage());

        // 可以根据不同的异常子类返回更精确的错误码
        if (e instanceof BadCredentialsException) {
            return Response.fail(ResponseCodeEnum.USERNAME_OR_PWD_ERROR); // "用户名或密码错误"
        } else if (e instanceof CredentialsExpiredException) {
            return Response.fail(ResponseCodeEnum.TOKEN_INVALID); // "Token失效，请重新登录"
        } else if (e instanceof UsernameNotFoundException) {
            return Response.fail(ResponseCodeEnum.USER_NOT_EXIST); // "用户不存在"
        } else {
            // 兜底的认证错误，例如请求头没带Token访问受保护资源
            return Response.fail(ResponseCodeEnum.UNAUTHORIZED); // "未经授权"
        }
    }

    /**
     * 处理权限不足异常（403）
     * 用户已认证，但没有访问该资源的权限
     */
    @ExceptionHandler(org.springframework.security.access.AccessDeniedException.class)
    public Response<Void> handleAccessDeniedException(org.springframework.security.access.AccessDeniedException e, HttpServletRequest req) {
        log.warn("[AccessDeniedException] {} -> {}", req.getRequestURI(), e.getMessage());
        return Response.fail(ResponseCodeEnum.FORBIDDEN); // "权限不足，禁止访问"
    }

    // ========== 你原有的异常处理方法保持不变 ==========

    /** 自定义业务异常 */
    @ExceptionHandler(BizException.class)
    public Response<Void> handleBiz(BizException e, HttpServletRequest req) {
        log.warn("[BizException] {} -> {}", req.getRequestURI(), e.getMessage());
        return Response.fail(e.getErrorCode(), e.getMessage());
    }

    /** 参数校验异常（@Valid 失败） */
    @ExceptionHandler(BindException.class)
    public Response<String> handleValid(BindException e, HttpServletRequest req) {
        String msg = e.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        log.warn("[BindException] {} -> {}", req.getRequestURI(), msg);
        return Response.fail(400000, msg);
    }

    /** 兜底：所有未捕获的运行期异常 */
    @ExceptionHandler(RuntimeException.class)
    public Response<Void> handleRuntime(RuntimeException e, HttpServletRequest req) {
        log.error("[RuntimeException] {} -> {}", req.getRequestURI(), e.getMessage(), e);
        return Response.fail("服务器开小差了，请稍后再试");
    }

    /** 兜底：所有未捕获的异常 */
    @ExceptionHandler(Exception.class)
    public Response<Void> handleAll(Exception e, HttpServletRequest req) {
        log.error("[Exception] {} -> {}", req.getRequestURI(), e.getMessage(), e);
        return Response.fail("系统繁忙，请联系管理员");
    }
}